<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  

  
  <title>从零开始搭建一个主流项目框架（六）——Socket网络编程 | 海晨忆的博客</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  
  
  
  <meta name="description" content="&amp;emsp;&amp;emsp;Android中常用的网络编程方式：Http和Socket，Http通讯方式，我们在前面已经加到框架里面了，用的是现在主流的RxJava+Retrofit+OkHttp的方式，用起来也很方便。今天，我们来说说Socket网络编程。前面已经有一篇讲过IO和NIO的区别，还有一篇讲过Netty了，今天这篇的目的就是把Netty加到我们这个框架里面。">
<meta property="og:type" content="article">
<meta property="og:title" content="从零开始搭建一个主流项目框架（六）——Socket网络编程">
<meta property="og:url" content="https://haichenyi.com/2018/02/26/从零开始搭建一个主流项目框架（六）—Socket网络编程/index.html">
<meta property="og:site_name" content="海晨忆的博客">
<meta property="og:description" content="&amp;emsp;&amp;emsp;Android中常用的网络编程方式：Http和Socket，Http通讯方式，我们在前面已经加到框架里面了，用的是现在主流的RxJava+Retrofit+OkHttp的方式，用起来也很方便。今天，我们来说说Socket网络编程。前面已经有一篇讲过IO和NIO的区别，还有一篇讲过Netty了，今天这篇的目的就是把Netty加到我们这个框架里面。">
<meta property="og:locale" content="zh-Hans">
<meta property="og:updated_time" content="2018-02-26T14:03:53.771Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="从零开始搭建一个主流项目框架（六）——Socket网络编程">
<meta name="twitter:description" content="&amp;emsp;&amp;emsp;Android中常用的网络编程方式：Http和Socket，Http通讯方式，我们在前面已经加到框架里面了，用的是现在主流的RxJava+Retrofit+OkHttp的方式，用起来也很方便。今天，我们来说说Socket网络编程。前面已经有一篇讲过IO和NIO的区别，还有一篇讲过Netty了，今天这篇的目的就是把Netty加到我们这个框架里面。">
  
    <link rel="alternate" href="/atom.xml" title="海晨忆的博客" type="application/atom+xml">
  
  
    <link rel="icon" href="/uploads/artistic_image/head.jpg">
  
  
    <link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
  
  <link rel="stylesheet" href="/css/style.css">
  <link rel="stylesheet" href="/css/highlight.css">
  <script>
  let antiquityStorage = window.sessionStorage.getItem('antiquitySessionStorage');
  if (antiquityStorage == '' || antiquityStorage == null) {
    var antiquityLoader = '<div id="loaderbox"><div class="loader"><div class="load-roll"><div class="load-top"></div><div class="load-right"></div><div class="load-bottom"></div></div></div></div>';
    document.write(antiquityLoader);
    document.body.style.overflow = 'hidden'
  }
  </script>
</head>

<body>
  <div id="fullpage" class="mobile-nav-right">
    
      <div id="wrapper" style="background-image: url(/uploads/artistic_image/bg.jpg)" title="背景图片来自网络">
    
    
      <header id="header">
  <div id="nav-toggle" class="nav-toggle"></div>
  <div class="head-box global-width">
    <nav class="nav-box nav-right">
      
        <a class="nav-item" href="/" title
        
        >首页</a>
      
        <a class="nav-item" href="/archives" title
        
        >归档</a>
      
        <a class="nav-item" href="/about" title
        
        >简历</a>
      
    </nav>
  </div>
</header>
      <div id="middlecontent" title class="global-width sidebar-left">
        <section id="main"><article id="post-从零开始搭建一个主流项目框架（六）—Socket网络编程" class="article global-container article-type-post" itemscope itemprop="blogPost">
  
    <header class="article-header">
      
  
    <h1 class="article-title" itemprop="name">
      从零开始搭建一个主流项目框架（六）——Socket网络编程
    </h1>
  

    </header>
  
  <div class="article-meta">
    <a href="/2018/02/26/从零开始搭建一个主流项目框架（六）—Socket网络编程/" class="article-date">
  <time datetime="2018-02-26T14:02:22.000Z" itemprop="datePublished">2018-02-26</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/Android-框架/">Android -框架</a>
  </div>

    
  </div>
  
    <span id="busuanzi_container_page_pv">
      本文总阅读量<span id="busuanzi_value_page_pv"></span>次
    </span>
  

  <div class="article-inner">
    
    <div class="article-content article-content-cloud doorframe mac" itemprop="articleBody">
      
        <p>&emsp;&emsp;Android中常用的网络编程方式：Http和Socket，Http通讯方式，我们在前面已经加到框架里面了，用的是现在主流的RxJava+Retrofit+OkHttp的方式，用起来也很方便。今天，我们来说说Socket网络编程。前面已经有一篇讲过IO和NIO的区别，还有一篇讲过Netty了，今天这篇的目的就是把Netty加到我们这个框架里面。</p>
<a id="more"></a>
<h3 id="添加依赖"><a href="#添加依赖" class="headerlink" title="添加依赖"></a>添加依赖</h3><div class="highlight-box"autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" contenteditable="true"data-rel="PLAIN"><figure class="iseeu highlight /plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation &apos;io.netty:netty-all:5.0.0.Alpha2&apos;</span><br></pre></td></tr></table></figure></div>
<p>添加依赖，老生常谈的问题了，我就不多说了。</p>
<h3 id="TCP"><a href="#TCP" class="headerlink" title="TCP"></a>TCP</h3><div class="highlight-box"autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" contenteditable="true"data-rel="PLAIN"><figure class="iseeu highlight /plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br></pre></td><td class="code"><pre><span class="line">package com.haichenyi.myproject.model.socket</span><br><span class="line"></span><br><span class="line">import android.util.Log</span><br><span class="line">import com.haichenyi.myproject.model.bean.SocketTcpBean</span><br><span class="line">import io.netty.bootstrap.Bootstrap</span><br><span class="line">import io.netty.channel.Channel</span><br><span class="line">import io.netty.channel.ChannelInitializer</span><br><span class="line">import io.netty.channel.ChannelOption</span><br><span class="line">import io.netty.channel.EventLoopGroup</span><br><span class="line">import io.netty.channel.nio.NioEventLoopGroup</span><br><span class="line">import io.netty.channel.socket.SocketChannel</span><br><span class="line">import io.netty.channel.socket.nio.NioSocketChannel</span><br><span class="line">import io.netty.handler.codec.LineBasedFrameDecoder</span><br><span class="line">import io.netty.handler.codec.string.StringDecoder</span><br><span class="line">import io.netty.handler.codec.string.StringEncoder</span><br><span class="line">import io.netty.util.CharsetUtil</span><br><span class="line">import org.greenrobot.eventbus.EventBus</span><br><span class="line">import org.greenrobot.eventbus.Subscribe</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * Author: 海晨忆</span><br><span class="line"> * Date: 2018/2/26</span><br><span class="line"> * Desc:</span><br><span class="line"> */</span><br><span class="line">class SocketTcp &#123;</span><br><span class="line">    companion object &#123;</span><br><span class="line">        private val socket = SocketTcp()</span><br><span class="line">        fun getInstance(): SocketTcp = socket</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    private var port: Int = 0</span><br><span class="line">    private var host: String = &quot;&quot;</span><br><span class="line">    private var channel: Channel? = null</span><br><span class="line">    private var group: EventLoopGroup? = null</span><br><span class="line">    fun setPort(port: Int): SocketTcp &#123;</span><br><span class="line">        this.port = port</span><br><span class="line">        return this</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    fun setHost(host: String): SocketTcp &#123;</span><br><span class="line">        this.host = host</span><br><span class="line">        return this</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    fun connect() &#123;</span><br><span class="line">        if (null != channel) return</span><br><span class="line">        if (null == group) &#123;</span><br><span class="line">            if (!EventBus.getDefault().isRegistered(this))</span><br><span class="line">                EventBus.getDefault().register(this)</span><br><span class="line">            group = NioEventLoopGroup()</span><br><span class="line">        &#125;</span><br><span class="line">        val bootstrap = Bootstrap()</span><br><span class="line">        try &#123;</span><br><span class="line">            bootstrap.group(group)</span><br><span class="line">                    .channel(NioSocketChannel::class.java)</span><br><span class="line">                    .option(ChannelOption.TCP_NODELAY, true)</span><br><span class="line">                    .handler(object : ChannelInitializer&lt;SocketChannel&gt;() &#123;</span><br><span class="line">                        override fun initChannel(ch: SocketChannel?) &#123;</span><br><span class="line">                            //以换行符为结束标记</span><br><span class="line">                            val pipeline = ch!!.pipeline()</span><br><span class="line">                            pipeline.addLast(&quot;encoder&quot;, StringEncoder(CharsetUtil.UTF_8))</span><br><span class="line">                            pipeline.addLast(LineBasedFrameDecoder(Integer.MAX_VALUE))</span><br><span class="line">                            pipeline.addLast(StringDecoder())</span><br><span class="line">                            pipeline.addLast(HeartTcp())</span><br><span class="line"></span><br><span class="line">                            //以&quot;#_&quot;作为分隔符</span><br><span class="line">                            /*val pipeline = ch!!.pipeline()</span><br><span class="line">                            pipeline.addLast(&quot;encoder&quot;, StringEncoder(CharsetUtil.UTF_8))</span><br><span class="line">                            val s = &quot;#_&quot;</span><br><span class="line">                            val byteBuf = Unpooled.copiedBuffer(s.toByteArray())</span><br><span class="line">                            pipeline.addLast(DelimiterBasedFrameDecoder(Integer.MAX_VALUE, byteBuf))</span><br><span class="line">                            pipeline.addLast(StringDecoder())*/</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;)</span><br><span class="line">            //发起异步连接操作</span><br><span class="line">            val channelFuture = bootstrap.connect(host, port).sync()</span><br><span class="line">            channel = channelFuture.channel()</span><br><span class="line">            //等待服务端监听端口关闭</span><br><span class="line">            channel!!.closeFuture().sync()</span><br><span class="line">        &#125; catch (e: Exception) &#123;</span><br><span class="line">            e.printStackTrace()</span><br><span class="line">        &#125; finally &#123;</span><br><span class="line">            disConnect()</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    //连接成功后，通过Channel提供的接口进行IO操作</span><br><span class="line">    fun sendMessage(msg: String) &#123;</span><br><span class="line">        try &#123;</span><br><span class="line">            if (channel != null &amp;&amp; channel!!.isOpen) &#123;</span><br><span class="line">                channel!!.writeAndFlush(msg).sync()</span><br><span class="line">                Log.d(&quot;wz&quot;, &quot;send succeed &quot; + msg)</span><br><span class="line">            &#125; else &#123;</span><br><span class="line">                throw Exception(&quot;channel is null | closed&quot;)</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; catch (e: Exception) &#123;</span><br><span class="line">            reConnect()</span><br><span class="line">            e.printStackTrace()</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 断开tcp连接.</span><br><span class="line">     */</span><br><span class="line">    private fun disConnect() &#123;</span><br><span class="line">        if (null != group) &#123;</span><br><span class="line">            group!!.shutdownGracefully()</span><br><span class="line">        &#125;</span><br><span class="line">//        EventBus.getDefault().unregister(this)</span><br><span class="line">        group = null</span><br><span class="line">        channel = null</span><br><span class="line">        Log.v(&quot;WZ&quot;, &quot;disConnect&quot;)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Subscribe</span><br><span class="line">    fun handle(socketTcpBean: SocketTcpBean) &#123;</span><br><span class="line">        sendMessage(socketTcpBean.msg)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 重连.</span><br><span class="line">     */</span><br><span class="line">    private fun reConnect() &#123;</span><br><span class="line">        Thread(Runnable &#123; this.connect() &#125;).start()</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>
<div class="highlight-box"autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" contenteditable="true"data-rel="PLAIN"><figure class="iseeu highlight /plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br></pre></td><td class="code"><pre><span class="line">package com.haichenyi.myproject.model.socket</span><br><span class="line"></span><br><span class="line">import android.os.SystemClock</span><br><span class="line">import android.util.Log</span><br><span class="line">import io.netty.buffer.Unpooled</span><br><span class="line">import io.netty.channel.ChannelHandlerContext</span><br><span class="line">import io.netty.channel.SimpleChannelInboundHandler</span><br><span class="line">import java.util.concurrent.TimeUnit</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">class HeartTcp : SimpleChannelInboundHandler&lt;Any&gt;() &#123;</span><br><span class="line">    private var ctx: ChannelHandlerContext? = null</span><br><span class="line">    private var isConnect = false</span><br><span class="line"></span><br><span class="line">    @Throws(Exception::class)</span><br><span class="line">    override fun channelActive(ctx: ChannelHandlerContext) &#123;</span><br><span class="line">        super.channelActive(ctx)</span><br><span class="line">        Log.v(&quot;WZ&quot;, &quot;连接正常channelActive&quot;)</span><br><span class="line">        isConnect = true</span><br><span class="line">        if (this.ctx == null) &#123;</span><br><span class="line">            synchronized(HeartTcp::class.java) &#123;</span><br><span class="line">                if (this.ctx == null) &#123;</span><br><span class="line">                    this.ctx = ctx</span><br><span class="line">                    myAppHeart()</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    private fun myAppHeart() &#123;</span><br><span class="line">        Thread &#123;</span><br><span class="line">            while (ctx != null &amp;&amp; isConnect) &#123;</span><br><span class="line">                val data = &quot;123&quot;</span><br><span class="line">                val bytes = data.toByteArray()</span><br><span class="line">                if (isConnect) &#123;</span><br><span class="line">                    ctx!!.writeAndFlush(Unpooled.buffer(bytes.size).writeBytes(bytes))</span><br><span class="line">                    SystemClock.sleep(3000)</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;.start()</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Throws(Exception::class)</span><br><span class="line">    override fun channelInactive(ctx: ChannelHandlerContext) &#123;</span><br><span class="line">        val loop = ctx.channel().eventLoop()</span><br><span class="line">        loop.schedule(&#123; SocketTcp.getInstance().connect() &#125;, 5, TimeUnit.SECONDS)</span><br><span class="line">        super.channelInactive(ctx)</span><br><span class="line">        Log.v(&quot;WZ&quot;, &quot;重新连接socket服务器&quot;)</span><br><span class="line">        isConnect = false</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Throws(Exception::class)</span><br><span class="line">    override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) &#123;</span><br><span class="line">        super.userEventTriggered(ctx, evt)</span><br><span class="line">        Log.v(&quot;WZ&quot;, &quot;发送数据包&quot;)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Throws(Exception::class)</span><br><span class="line">    override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) &#123;</span><br><span class="line">        super.exceptionCaught(ctx, cause)</span><br><span class="line">        Log.v(&quot;WZ&quot;, &quot;连接出现异常&quot;)</span><br><span class="line">        this.ctx = null</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Throws(Exception::class)</span><br><span class="line">    override fun messageReceived(ctx: ChannelHandlerContext, msg: Any) &#123;</span><br><span class="line">        Log.v(&quot;WZ&quot;, &quot;连接正常messageReceived&quot;)</span><br><span class="line">        /*val msg1 = msg</span><br><span class="line">        val bytes = ByteArray(msg1.readableBytes())</span><br><span class="line">        msg1.readBytes(bytes)</span><br><span class="line">        val s = String(bytes*//*, &quot;UTF-8&quot;*//*)*/</span><br><span class="line">        val s = msg.toString()</span><br><span class="line">        Log.v(&quot;WZ&quot;, &quot;接收到的消息:&quot; + s)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>
<p>&emsp;&emsp;我这里就是把我前面那个讲Netty创建Socket连接的代码拷贝过来转成了kotlin代码，这里我就不做过多的解释了。</p>
<p>&emsp;&emsp;一般，我们都是后台新开一个服务去启动socket，所以，我们还要创建一个Service，去处理socket。我这里就是非绑定启动这个服务。在oncreate方法里面去连接服务器即可</p>
<div class="highlight-box"autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" contenteditable="true"data-rel="PLAIN"><figure class="iseeu highlight /plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">package com.haichenyi.myproject.model.socket</span><br><span class="line"></span><br><span class="line">import android.app.Service</span><br><span class="line">import android.content.Intent</span><br><span class="line">import android.os.IBinder</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * Author: 海晨忆</span><br><span class="line"> * Date: 2018/2/26</span><br><span class="line"> * Desc:</span><br><span class="line"> */</span><br><span class="line">class SocketService : Service() &#123;</span><br><span class="line">    override fun onBind(intent: Intent?): IBinder? &#123;</span><br><span class="line">        return null</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    override fun onCreate() &#123;</span><br><span class="line">        super.onCreate()</span><br><span class="line">        Thread(Runnable &#123; SocketTcp.getInstance().setPort(8080).setHost(&quot;192.168.0.235&quot;).connect() &#125;).start()</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>
<p>&emsp;&emsp;之所以要新建一个服务，就是可能你在连接socket的时候，可能要做一些其他信息的初始化，而这些信息初始化也是只有在连接socket服务器之前才需要的，写在这里方便一起管理，要是写在activity里面不便于管理。上面都是扯淡，最主要的是我们在最初学Android的时候，教你们的老师应该讲过，什么时候需要用到服务，就是不需要页面，用户并不关心它长什么样子，需要长连接的任务，都放在服务里面。正好，socket连接正好满足这些条件。</p>
<p>&emsp;&emsp;细心的同学可能注意了，我在Tcp类里面有一个EventBus，我这里是把发TCP消息给拿出来了，便于管理。我这边还新建了一个SocketUtils类，就是处理Socket请求的方法，我们发消息之类的方法，都是调用SocketUtils类里面的方法，不用去改Tcp类。这样做就只有一个目的，就是便于统一管理，代码如下</p>
<div class="highlight-box"autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" contenteditable="true"data-rel="PLAIN"><figure class="iseeu highlight /plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">package com.haichenyi.myproject.model.socket</span><br><span class="line"></span><br><span class="line">import com.haichenyi.myproject.model.bean.SocketTcpBean</span><br><span class="line">import org.greenrobot.eventbus.EventBus</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * Author: 海晨忆</span><br><span class="line"> * Date: 2018/2/26</span><br><span class="line"> * Desc:</span><br><span class="line"> */</span><br><span class="line">object SocketUtils &#123;</span><br><span class="line">    fun sendTcpMsg(msg: String) &#123;</span><br><span class="line">        sendTcpMsg(SocketTcpBean(msg))</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    private fun sendTcpMsg(socketTcpBean: SocketTcpBean) &#123;</span><br><span class="line">        EventBus.getDefault().post(socketTcpBean)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>
<p>&emsp;&emsp;至于这个SocketTcpBean类，就是一个普通的java bean类，里面就只有一个参数msg，你需要发的消息</p>
<h3 id="UDP"><a href="#UDP" class="headerlink" title="UDP"></a>UDP</h3><p>我先给出来代码</p>
<div class="highlight-box"autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" contenteditable="true"data-rel="PLAIN"><figure class="iseeu highlight /plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br></pre></td><td class="code"><pre><span class="line">package com.haichenyi.myproject.model.socket</span><br><span class="line"></span><br><span class="line">import android.util.Log</span><br><span class="line">import com.haichenyi.myproject.model.bean.SocketUdpBean</span><br><span class="line">import io.netty.bootstrap.Bootstrap</span><br><span class="line">import io.netty.buffer.Unpooled</span><br><span class="line">import io.netty.channel.Channel</span><br><span class="line">import io.netty.channel.ChannelOption</span><br><span class="line">import io.netty.channel.EventLoopGroup</span><br><span class="line">import io.netty.channel.nio.NioEventLoopGroup</span><br><span class="line">import io.netty.channel.socket.DatagramPacket</span><br><span class="line">import io.netty.channel.socket.nio.NioDatagramChannel</span><br><span class="line">import org.greenrobot.eventbus.EventBus</span><br><span class="line">import org.greenrobot.eventbus.Subscribe</span><br><span class="line">import java.net.InetSocketAddress</span><br><span class="line">import java.nio.charset.Charset</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * Author: 海晨忆</span><br><span class="line"> * Date: 2018/2/26</span><br><span class="line"> * Desc:</span><br><span class="line"> */</span><br><span class="line">class SocketUdp &#123;</span><br><span class="line">    companion object &#123;</span><br><span class="line">        private val socket = SocketUdp()</span><br><span class="line">        fun getInstance(): SocketUdp = socket</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    private var port: Int = 0</span><br><span class="line">    private var channel: Channel? = null</span><br><span class="line">    private var group: EventLoopGroup? = null</span><br><span class="line"></span><br><span class="line">    fun setPort(port: Int): SocketUdp &#123;</span><br><span class="line">        this.port = port</span><br><span class="line">        return this</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    fun connect() &#123;</span><br><span class="line">        if (null != channel) return</span><br><span class="line">        if (null == group) &#123;</span><br><span class="line">            if (!EventBus.getDefault().isRegistered(this))</span><br><span class="line">                EventBus.getDefault().register(this)</span><br><span class="line">            group = NioEventLoopGroup()</span><br><span class="line">        &#125;</span><br><span class="line">        val bootstrap = Bootstrap()</span><br><span class="line">        bootstrap.group(group)</span><br><span class="line">                .channel(NioDatagramChannel::class.java)</span><br><span class="line">                .option(ChannelOption.SO_BROADCAST, true)</span><br><span class="line">                .handler(UdpHandler())</span><br><span class="line">        try &#123;</span><br><span class="line">            channel = bootstrap.bind(port).sync().channel()</span><br><span class="line">            channel!!.closeFuture().sync()</span><br><span class="line">        &#125; catch (e: InterruptedException) &#123;</span><br><span class="line">            e.printStackTrace()</span><br><span class="line">        &#125; finally &#123;</span><br><span class="line">            disConnect()</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 断开tcp连接.</span><br><span class="line">     */</span><br><span class="line">    private fun disConnect() &#123;</span><br><span class="line">        if (null != group) &#123;</span><br><span class="line">            group!!.shutdownGracefully()</span><br><span class="line">        &#125;</span><br><span class="line">//        EventBus.getDefault().unregister(this)</span><br><span class="line">        group = null</span><br><span class="line">        channel = null</span><br><span class="line">        Log.v(&quot;WZ&quot;, &quot;disConnect&quot;)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    //连接成功后，通过Channel提供的接口进行IO操作</span><br><span class="line">    private fun sendMessage(host: String, port: Int, data: ByteArray) &#123;</span><br><span class="line">        val packet = DatagramPacket(Unpooled.copiedBuffer(data),</span><br><span class="line">                InetSocketAddress(host, port))</span><br><span class="line">        channel?.let &#123;</span><br><span class="line">            try &#123;</span><br><span class="line">                it.writeAndFlush(packet).sync()</span><br><span class="line">                Log.d(&quot;wz&quot;, &quot;send succeed &quot; + String(data, Charset.forName(&quot;UTF-8&quot;)))</span><br><span class="line">            &#125; catch (e: Exception) &#123;</span><br><span class="line">                reConnect()</span><br><span class="line">                e.printStackTrace()</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Subscribe</span><br><span class="line">    fun handle(socketUdpBean: SocketUdpBean) &#123;</span><br><span class="line">        sendMessage(socketUdpBean.host,socketUdpBean.port,socketUdpBean.data)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 重连.</span><br><span class="line">     */</span><br><span class="line">    private fun reConnect() &#123;</span><br><span class="line">        Thread(Runnable &#123; this.connect() &#125;).start()</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>
<div class="highlight-box"autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" contenteditable="true"data-rel="PLAIN"><figure class="iseeu highlight /plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">package com.haichenyi.myproject.model.socket</span><br><span class="line"></span><br><span class="line">import android.util.Log</span><br><span class="line">import io.netty.channel.ChannelHandlerContext</span><br><span class="line">import io.netty.channel.SimpleChannelInboundHandler</span><br><span class="line">import io.netty.channel.socket.DatagramPacket</span><br><span class="line">import java.nio.charset.Charset</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * Author: 海晨忆</span><br><span class="line"> * Date: 2018/2/26</span><br><span class="line"> * Desc:</span><br><span class="line"> */</span><br><span class="line">class UdpHandler : SimpleChannelInboundHandler&lt;DatagramPacket&gt;() &#123;</span><br><span class="line"></span><br><span class="line">    override fun messageReceived(ctx: ChannelHandlerContext?, msg: DatagramPacket?) &#123;</span><br><span class="line">        val byteBuf = msg!!.content()</span><br><span class="line">        val bytes = ByteArray(byteBuf.readableBytes())</span><br><span class="line">        byteBuf.readBytes(bytes)</span><br><span class="line">        val s = String(bytes, Charset.forName(&quot;UTF-8&quot;))</span><br><span class="line">        Log.v(&quot;WZ&quot;, &quot;UDP收到的消息是--&gt;$s&quot;)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>
<p>&emsp;&emsp;这里的代码跟TCP类似，我想说的就只有三点：</p>
<ol>
<li>首先你客户端开启UDP的时候，需要bind一个端口号，这个端口号是服务器给你发消息的时候，需要的端口号。</li>
<li>它的管道里面的handle类型DatagramPacket</li>
<li>再有就是给目标主机发消息，UDP需要传目标地址，端口号，还有消息。这里的目标地址就是服务器的地址，端口号就是服务器跟你通信的端口号，消息就是你需要发送给服务器的信息</li>
</ol>
<p>&emsp;&emsp;其实，这里的区别就是TCP与UDP的区别，TCP和UDP什么区别呢？</p>
<table>
<thead>
<tr>
<th style="text-align:center">类型</th>
<th style="text-align:center">TCP</th>
<th style="text-align:center">UDP</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">是否连接</td>
<td style="text-align:center">面向连接</td>
<td style="text-align:center">面向非连接</td>
</tr>
<tr>
<td style="text-align:center">传输效率</td>
<td style="text-align:center">慢</td>
<td style="text-align:center">快</td>
</tr>
<tr>
<td style="text-align:center">数据是否有序</td>
<td style="text-align:center">有序</td>
<td style="text-align:center">无序</td>
</tr>
<tr>
<td style="text-align:center">安全性</td>
<td style="text-align:center">安全</td>
<td style="text-align:center">不安全</td>
</tr>
<tr>
<td style="text-align:center">模式</td>
<td style="text-align:center">流模式</td>
<td style="text-align:center">报文模式</td>
</tr>
<tr>
<td style="text-align:center">系统资源</td>
<td style="text-align:center">多</td>
<td style="text-align:center">少</td>
</tr>
</tbody>
</table>
<p>区别的总结：最典型的对比就是打电话（TCP）和发短信（UDP）的区别</p>
<ol>
<li>是否连接方面，TCP是1对1，UDP可以1对N</li>
<li>传输效率：TCP必须等到一个消息全部传完了才能传下一个，UDP可以一直发</li>
<li>数据是否有序：TCP是按顺序一条一条的发，当然是有序的。UDP则是无序的</li>
<li>安全性方面：TCP有3次握手机制，采用的全双工的可靠信道，保证了数据的安全，UDP则没有3次握手机制，采用的是不可靠信道</li>
<li>模式方面：TCP是面向字节流，实际上TCP把数据看成了一连串无结构的字节流，UDP则是面向报文的</li>
<li>系统资源方面：TCP首部开销20个字节，UDP首部开销8个字节</li>
</ol>
<p><a href="http://download.csdn.net/download/qq_27634797/10260329" target="_blank" rel="noopener">项目链接</a></p>

      
    </div>
    
      <footer class="article-footer">
        完
      </footer>
    
  </div>
  
    
<nav id="article-nav">
  <div class="article-nav-block">
    
      <a href="/2018/03/01/从零开始搭建一个主流项目框架（七）—权限申请-Android6.0/" id="article-nav-newer" class="article-nav-link-wrap">
        <strong class="article-nav-caption"></strong>
        <div class="article-nav-title">
          
            从零开始搭建一个主流项目框架（七）—— 权限申请(Android 6.0)
          
        </div>
      </a>
    
  </div>
  <div class="article-nav-block">
    
      <a href="/2018/02/24/从零开始搭建一个主流项目框架（五）—GreenDao的增删改查/" id="article-nav-older" class="article-nav-link-wrap">
        <div class="article-nav-title">从零开始搭建一个主流项目框架（五）—GreenDao的增删改查</div>
        <strong class="article-nav-caption"></strong>
      </a>
    
  </div>
</nav>

    
  
  
</article>
</section>
        <aside id="sidebar">
  
    <div class="widget-box">
  <div class="avatar-box avatar-item">
    <img class="avatar" src="/uploads/artistic_image/head.jpg" title="头像来自网络"></img>
    <h3 class="avatar-name">
      
        海晨忆
      
    </h3>
    <p class="avatar-slogan">
      先谋生，再谋爱。人间值得，未来可期。
    </p>
  </div>
</div>


  
    
  <div class="widget-box">
    <h3 class="widget-title">分类</h3>
    <div class="widget">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/Android-Socket/">Android -Socket</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-加密算法/">Android -加密算法</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-常用功能/">Android -常用功能</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-框架/">Android -框架</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-源码解析/">Android -源码解析</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-自定义view/">Android -自定义view</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-设计模式/">Android -设计模式</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/JAVA-并发/">JAVA -并发</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Java-SpringBoot/">Java -SpringBoot</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Tomcat/">Tomcat</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/kotlin/">kotlin</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/数据库-JDBC/">数据库 -JDBC</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/数据库-MySQL/">数据库 -MySQL</a></li></ul>
    </div>
  </div>


  
    

  
    
  
    
  <div class="widget-box">
    <h3 class="widget-title">归档</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/07/">July 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/11/">November 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/10/">October 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/09/">September 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/08/">August 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/07/">July 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/06/">June 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/10/">October 2018</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/05/">May 2018</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/03/">March 2018</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/02/">February 2018</a></li></ul>
    </div>
  </div>

  
    
  <div class="widget-box">
    <h3 class="widget-title">最新文章</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/2021/07/27/JAVA—公平锁，非公平锁，悲观锁，乐观锁，死锁/">JAVA—公平锁，非公平锁，悲观锁，乐观锁，死锁</a>
          </li>
        
          <li>
            <a href="/2021/07/19/JAVA—线程同步器AQS/">JAVA—线程同步器AQS</a>
          </li>
        
          <li>
            <a href="/2021/07/07/Android模拟点击/">Android模拟点击</a>
          </li>
        
          <li>
            <a href="/2019/11/27/SpringBoot系列-消息-RabbitMQ-（二十）/">SpringBoot系列-消息(RabbitMQ)（二十）</a>
          </li>
        
          <li>
            <a href="/2019/11/13/SpringBoot系列-Docker（十九）/">SpringBoot系列-Docker（十九）</a>
          </li>
        
      </ul>
    </div>
  </div>

  
      <div class="widget-box">
    <h3 class="widget-title">友情链接</h3>
    <div class="widget">
      
        <a class="hrf" style="display: block;" href="https://github.com/haichenyi" title target='_blank'
        >Github</a>
      
        <a class="hrf" style="display: block;" href="https://www.jianshu.com/u/6077ee440c37" title target='_blank'
        >简书</a>
      
        <a class="hrf" style="display: block;" href="https://blog.csdn.net/qq_27634797" title target='_blank'
        >CSDN</a>
      
    </div>
  </div>

  
</aside>
      </div>
      <footer id="footer">
  <div class="foot-box footers global-width">
    &copy;2017-2021 海晨忆 &nbsp;&nbsp;
    <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    <span id="busuanzi_container_site_pv">阁下是第<span id="busuanzi_value_site_pv"></span>个访客</span>
  </div>
</footer>
      <script src="https://code.jquery.com/jquery-2.0.3.min.js"></script>
<script>
if (!window.jQuery) {
var script = document.createElement('script');
script.src = "/js/jquery-2.0.3.min.js";
document.body.write(script);
}
</script>

  <link rel="stylesheet" href="/fancybox/jquery.fancybox.css">
  <script src="/fancybox/jquery.fancybox.pack.js"></script>


<script src="/js/script.js"></script>



    </div>
    <nav id="mobile-nav" class="mobile-nav-box">
  <div class="mobile-nav-img mobile-nav-top"></div>
  
    <a href="/" class="mobile-nav-link">首页</a>
  
    <a href="/archives" class="mobile-nav-link">归档</a>
  
    <a href="/about" class="mobile-nav-link">简历</a>
  
  <div class="mobile-nav-img  mobile-nav-bottom"></div>
</nav>    
  </div>
</body>
</html>